#include <chrono>
#include <future>
#include <thread>

#include <logger.h>

using namespace std::chrono_literals;

int main()
{
    {
        LOG0SO(INFO) << "packaged_task把函数包装成异步函数，可执行，可future";
        auto func = [](int a, int b) { return a * b; };
        std::packaged_task<int(int, int)> task(func);
        std::future<int> result = task.get_future();
        auto execTask = [&task]() {
            std::this_thread::sleep_for(1s);
            LOG0SO(INFO) << "exec";
            task(3, 4);
        };
        auto _ = std::async(execTask);
        LOG0SO(INFO) << "getting";
        LOG0SO(INFO) << "get: " << result.get();
    }

    {
        LOG0SO(INFO) << "promise把任意过程包装成异步值获取器，可设置，可future";
        std::promise<int> p1, p2;
        auto func = [&p1, &p2](int a, int b) {
            std::this_thread::sleep_for(1s);
            p1.set_value(a);
            std::this_thread::sleep_for(1s);
            p2.set_value(b);
        };

        std::future<int> result1 = p1.get_future();
        std::future<int> result2 = p2.get_future();
        auto _ = std::async(func, 1, 2);
        LOG0SO(INFO) << "getting";
        LOG0SO(INFO) << "get: " << result1.get();
        LOG0SO(INFO) << "get: " << result2.get();
    }

    {
        std::future<int> result;
        {
            LOG0SO(INFO) << "promise可移动";
            std::promise<int> promise;
            result = promise.get_future();
            auto func = [](int a, std::promise<int> promise) {
                std::this_thread::sleep_for(1s);
                promise.set_value(a);
            };

            auto _ = std::async(func, 1, std::move(promise));
        }
        LOG0SO(INFO) << "getting";
        LOG0SO(INFO) << "get: " << result.get();
    }

    {
        std::future<int> result;
        {
            LOG0SO(INFO) << "promise立刻返回";
            std::promise<int> promise;
            result = promise.get_future();
            promise.set_value(3);
        }
        LOG0SO(INFO) << "getting";
        LOG0SO(INFO) << "get: " << result.get();
    }
    return 0;
}
